package cn.edu.nit.sys.config;

import cn.edu.nit.sys.entity.SysLog;
import cn.edu.nit.sys.mapper.SysLogMapper;
import cn.edu.nit.sys.utils.JwtUtils;
import com.mysql.cj.util.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author xiaobai
 * @Date 2022/8/30 19:33
 * @Version 1.0.0
 */
@Aspect
@Component
@EnableAsync
public class SysLogAspect {

    @Autowired
    private SysLogMapper sysLogMapper;

    private String requestPath;
    private Long startTime;
    private Long endTime;
    private String user;
    private HttpServletRequest request;

    @Pointcut("@annotation(cn.edu.nit.sys.config.OperationAnnotation)")
    public void logPointCut() {}

    @Before(value = "logPointCut()")
    public void before(JoinPoint joinPoint) {
        startTime = System.currentTimeMillis();
    }

    public Map<String, Object> getValue(JoinPoint joinPoint) {
        Map<String, Object> map = new HashMap<>();
        Object[] args = joinPoint.getArgs();
        String[] parameterNames = ((CodeSignature) joinPoint.getSignature()).getParameterNames();
        for (int i = 0; i < parameterNames.length; i++) {
            if(args[i] instanceof Integer || args[i] instanceof String) {
                map.put(parameterNames[i], args[i]);
            }
        }
        return map;
    }

    @After(value = "logPointCut()")
    public void after(JoinPoint joinPoint) {
        request = getRequest();
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class<?> targetClass = null;
        try {
            targetClass = Class.forName(targetName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Method[] methods = targetClass.getMethods();
        String title;
        String action;
        Integer sysType;
        String opType;
        Class<?>[] clazzs;
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                clazzs = method.getParameterTypes();
                if (clazzs!=null&&clazzs.length == arguments.length
                        &&method.getAnnotation(OperationAnnotation.class)!=null) {
                    request = getRequest();
                    requestPath = request.getServletPath();
                    title = method.getAnnotation(OperationAnnotation.class).description();
                    opType = method.getAnnotation(OperationAnnotation.class).opType();
                    endTime = System.currentTimeMillis();

                    String username = null;
                    String IP = request.getHeader("x-forwarded-for");
                    if(requestPath.indexOf("login") == -1) {
                        Map<String, Object> infoFromToken = JwtUtils.getInfoFromToken(request);
                        if(StringUtils.isNullOrEmpty(infoFromToken.get("username").toString())) {
                            username = "";
                        }else {
                            username = infoFromToken.get("username").toString();
                        }
                    }
                    String userAgent = request.getHeader("User-Agent");
                    SysLog log = new SysLog(username, IP, requestPath,
                            getValue(joinPoint).toString(), title, opType, userAgent, System.currentTimeMillis());
                    sysLogMapper.insert(log);
                }
            }
        }
    }

    private HttpServletRequest getRequest() {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) attributes;
        return requestAttributes.getRequest();
    }


    public Object around(JoinPoint joinPoint) throws Throwable {
        return null;
    }

    public void throwing(JoinPoint joinPoint) {
        System.out.println("异常");
    }
}
